
typedef logic[1:0] isu_wcnt_t;
typedef logic[NUM_ISU_OCNT:0] isu_ocnt_t;
typedef logic[WID_ISU_OCNT-1:0] isu_oid_t;
typedef logic[WID_THRD_GRP-1:0] grpid_t;
typedef logic[19:0] imm_t;
typedef iop21_e opcode_t;

typedef enum logic[1:0] {
  it_int, it_flt, it_lsu, it_ext
} inst_typ_e;

typedef logic[3:0] inst_filter_t;

typedef enum logic[3:0] {
  ts_disabled,  ts_rdy,   ts_w_if,     ts_w_lsex,
  ts_lsex_w_if, ts_w_br,  ts_br_w_if,  ts_br_cl,
  ts_w_pip///,     ts_w_ex,  ts_ex_w_if
}thrd_state_t;

typedef enum logic[2:0] {
  opsz,    opsr,  opsi,   opsc,  opsm,    opsf
}isu_opsel_t;

typedef enum logic[1:0] {
  pts[0:2],    ptsn
}isu_ptsel_t;

typedef logic[WID_VRF_BKS - 1:0] vrfbk_t;
typedef logic[WID_VRF_ADR - 1:0] vrfadr_t;
typedef logic[WID_SRF_ADR - 1:0] srfadr_t;
typedef logic[WID_SRF_BKS - 1:0] srfbk_t;

typedef logic[WID_INST_BUF - 1:0] ibuf_adr_t;
typedef logic[4:0] irf_adr_t;

typedef enum logic[3:0] {
  cop_e,    cop_g,    cop_ge,    cop_l,   cop_le,
  cop_ug,   cop_uge,  cop_ul,    cop_ule
} cmp_opcode_e;

typedef enum logic {
  bop_az,     bop_naz
} br_opcode_e;

typedef enum logic[1:0] {
  priv_user,    priv_kernel,  priv_event
}priv_mode_t;

typedef struct{
  logic vec;
  isu_opsel_t ops;
  vrfbk_t bks;
  cyc_t cyc;
} isu_brf_radr_s;

parameter isu_brf_radr_s isu_brf_radr_def = '{
  ops       : opsz,
  default   : '0
};

typedef struct{
  irf_adr_t adr;
  logic vec, dw, wr;
  isu_opsel_t ops;
} isu_rf_adr_s;

parameter isu_rf_adr_s isu_rf_adr_def = '{
  ops       : opsz,
  default   : '0
};

typedef struct{
  logic req, last;
  vrfadr_t vradr[NUM_LANE][NUM_VRF_BKS], vwadr[NUM_LANE][NUM_VRF_BKS];
  srfadr_t sadr[NUM_LANE][NUM_SRF_BKS],
           swadr[NUM_SRF_BKS];
  lid_t swLid[NUM_SRF_BKS];
  logic[1:0] fuWSel[NUM_LANE][NUM_VRF_BKS];
  logic vwr[NUM_LANE][NUM_VRF_BKS],
        swr[NUM_SRF_BKS];
  isu_brf_radr_s fuRrf[NUM_FU], lsRrf;
  isu_ptsel_t fuPts[NUM_FU];
  isu_ptsel_t lsPts;
  lid_t spLid, lsLid, fuLid[NUM_FU];
  ltid_t spLtid;
  irf_adr_t spAdr[2];
  srfbk_t spBks;
  isu_opsel_t spOps[3];
  imm_t fuImm[NUM_FU], lsImm, spImm;
  word spPC;
  logic[1:0] exFu;
  logic lsuRsp, exuRsp;
} isu2rfu_s;
  
parameter isu2rfu_s isu2rfu_def = '{
  vradr   : '{default : '0},
  vwadr   : '{default : '0},
  sadr    : '{default : '0},
  swadr   : '{default : '0},
  swLid   : '{default : '0},
  vwr     : '{default : '0},
  swr     : '{default : '0},
  fuLid   : '{default : '0},
  fuWSel  : '{default : '1},
  fuRrf   : '{default : isu_brf_radr_def},
  fuPts   : '{default : ptsn},
  lsRrf   : isu_brf_radr_def,
  lsPts   : ptsn,
  spAdr   : '{default : '0},
  spOps   : '{default : opsz},
  fuImm   : '{default : '0},
  default : '0
};

typedef struct{
  logic req[NUM_LANE], br;
  word pc;
  ltid_t ltid[NUM_LANE], brLtid;
  lid_t brLid;
} isu2ifu_s;

parameter isu2ifu_s isu2ifu_def = '{
  req        : '{default : '0},
  ltid       : '{default : '0},
  default    : '0
};

typedef struct{
  logic rsp[NUM_LANE];
  ilo_inst_s inst[NUM_LANE];
  ltid_t ltid[NUM_LANE];
  word pc[NUM_LANE];
} ifu2isu_s;

parameter ifu2isu_s ifu2isu_def = '{
  rsp       : '{default : '0},
  inst      : '{default : '0},
  ltid      : '{default : '0},
  pc        : '{default : '0},
  default   : '0
};

typedef struct{
  logic last, srRsp;
  opcode_t fuOP[NUM_FU], spOP;
  logic fuReq[NUM_FU], spEn;
  word sr;
  grpid_t spGid;
} isu2dpu_s;
  
parameter isu2dpu_s isu2dpu_def = '{
  fuOP    : '{default : op_nop},
  spOP    : op_nop,
  fuOP    : '{default : '0},
  default : '0
};

typedef struct{
  logic req;
  word data;
} dpu2isu_s;
  
parameter dpu2isu_s dpu2isu_def = '{
  default : '0
};

typedef struct{
  irf_adr_t adr;
  logic vblock, req,
        asyn, ls, crfw;
  lid_t lid;
  ltid_t ltid;
  isu_oid_t oid;
} lsu2isu_s;
  
parameter lsu2isu_s lsu2isu_def = '{
  default : '0
};

typedef struct{
  irf_adr_t adr;
  logic sblock, req,
        asyn, ls;
  lid_t lid;
  ltid_t ltid;
  isu_oid_t oid;
} sau2isu_s;
  
parameter sau2isu_s sau2isu_def = '{
  default : '0
};

typedef struct{
  logic rsp;
} isu2sau_s;
  
parameter isu2sau_s isu2sau_def = '{
  default : '0
};

typedef struct{
  logic req, last, rsp, asyn;
  isu_rf_adr_s wrf;
  ltid_t ltid;
  lid_t lid;
  isu_oid_t oid;
  logic ls, lg;
  logic[1:0] ch, prot;
  logic[3:0] fun;
  grpid_t gid;
  logic sRf[NUM_SRF_BKS], vRf[NUM_LANE][NUM_VRF_BKS];
} isu2lsu_s;
  
parameter isu2lsu_s isu2lsu_def = '{
  sRf     : '{default : '0},
  vRf     : '{default : '0},
  wrf     : isu_rf_adr_def,
  default : '0
};

typedef struct{
  irf_adr_t adr;
  logic vblock, sblock, req, asyn, ls, vs;
  lid_t lid;
  ltid_t ltid;
  isu_oid_t oid;
} exu2isu_s;
  
parameter exu2isu_s exu2isu_def = '{
  default : '0
};

typedef struct{
  logic sRf[NUM_SRF_BKS], vRf[NUM_LANE][NUM_VRF_BKS];
  logic req, last, rsp;
  isu_rf_adr_s wrf;
  ltid_t ltid;
  lid_t lid;
  opcode_t opcode;
} isu2exu_s;
  
parameter isu2exu_s isu2exu_def = '{
  vRf     : '{default : '0},
  sRf     : '{default : '0},
  wrf     : isu_rf_adr_def,
  opcode  : op_nop,
  default : '0
};

typedef struct{
  thrd_state_t ts;
  inst_typ_e it;
  logic vec, asyn;
  isu_wcnt_t vwcnt;
  cyc_t swcnt;
  cyc_t vbkCnt[NUM_VRF_BKS];
  cyc_t sbkCnt[NUM_SRF_BKS];
  isu_rf_adr_s rrf[3];
  isu_rf_adr_s wrf;
  word pc;
  imm_t imm;
  opcode_t opcode;
  isu_ocnt_t ocnt[3], omsk[3];
  isu_oid_t[NUM_ISU_OCNT-1:0] oid[3];
  logic sblock[2];
  grpid_t gid;
} isu_thrd_inf_s;
  
parameter isu_thrd_inf_s isu_thrd_inf_def = '{
  ts        : ts_w_if,
  it        : it_int,
  vbkCnt    : '{default : '0},
  sbkCnt    : '{default : '0},
  rrf       : '{default : isu_rf_adr_def},
  wrf       : isu_rf_adr_def,
  opcode    : op_nop,
  ocnt      : '{default : '0},
  omsk      : '{default : '0},
  oid       : '{default : '0},
  sblock    : '{default : '0},
  default   : '0
};

typedef struct{
  logic en, vec;
  isu_rf_adr_s rrf[3];
  isu_rf_adr_s wrf;
  imm_t imm;
  word pc;
  inst_typ_e it;
  ltid_t pfTid, ltid;
  logic s3Forb, siRdy;///siForb, 
  inst_filter_t viFilter, viPrefer, viRdy, siFilter;
  cyc_t vFilter[NUM_VRF_BKS];
  cyc_t sFilter[NUM_SRF_BKS];
  opcode_t opcode;
  grpid_t gid;
  isu_oid_t oid;
  logic asyn;
} isu_lane_inf_s;
  
parameter isu_lane_inf_s isu_lane_inf_def = '{
  rrf       : '{default : isu_rf_adr_def},
  wrf       : isu_rf_adr_def,
  vFilter   : '{default : MCV - 1},
  sFilter   : '{default : MCV - 1},
  it        : it_int,
  opcode    : op_nop,
  default   : '0
};

typedef struct{
  vrfadr_t vadr[NUM_VRF_BKS];
  srfadr_t sadr[NUM_SRF_BKS];
  logic vwr[NUM_VRF_BKS],
        ven[NUM_VRF_BKS],
        sen[NUM_SRF_BKS];
} isu_rf_inf_s;
  
parameter isu_rf_inf_s isu_rf_inf_def = '{
  vadr      : '{default: '0},
  sadr      : '{default: '0},
  vwr       : '{default: '0},
  ven       : '{default: '0},
  sen       : '{default: '0},
  default   : '0
};

typedef struct{
  logic en;
  isu_brf_radr_s rrf[3];
  isu_rf_adr_s wrf;
  ltid_t ltid;
  lid_t lid;
  opcode_t opcode;
  imm_t imm;
} isu_fui3_inf_s;
  
parameter isu_fui3_inf_s isu_fui3_inf_def = '{
  rrf       : '{default : isu_brf_radr_def},
  wrf       : isu_rf_adr_def,
  opcode    : op_nop,
  default   : '0
};

typedef struct{
  logic en;
  isu_brf_radr_s rrf[2];
  ltid_t ltid;
  lid_t lid;
  isu_rf_adr_s wrf;
  opcode_t opcode;
  imm_t imm;
  grpid_t gid;
  isu_oid_t oid;
  logic asyn;
} isu_lsi2_inf_s;
  
parameter isu_lsi2_inf_s isu_lsi2_inf_def = '{
  rrf       : '{default : isu_brf_radr_def},
  wrf       : isu_rf_adr_def,
  opcode    : op_nop,
  default   : '0
};

typedef struct{
  logic en;
  ltid_t ltid;
  lid_t lid;
  isu_rf_adr_s wrf;
  isu_rf_adr_s rrf[3];
  opcode_t opcode;
  imm_t imm;
  word pc;
  grpid_t gid;
} isu_spi_inf_s;
  
parameter isu_spi_inf_s isu_spi_inf_def = '{
  rrf       : '{default : isu_rf_adr_def},
  wrf       : isu_rf_adr_def,
  opcode    : op_nop,
  default   : '0
};

typedef struct{
  lid_t l, vext;
  isu_oid_t exoid;
  logic exasyn;
  logic[1:0] exFu;
  vrfadr_t vrfadr[NUM_LANE][NUM_VRF_BKS];
  srfadr_t srfadr[NUM_SRF_BKS];
  lid_t srflid[NUM_SRF_BKS];
  logic srfwv[NUM_SRF_BKS],
        vrfwv[NUM_LANE][NUM_VRF_BKS];
} isu_inf_s;
  
parameter isu_inf_s isu_inf_def = '{
  srfwv     : '{default : '0},
  vrfwv     : '{default : '0},
  default   : '0
};

typedef struct{
  ifu2isu_s ifu;
  dpu2isu_s dpu;
  lsu2isu_s lsu;
  sau2isu_s sau;
  exu2isu_s exu;
} isu_io_inf_s;
  
parameter isu_io_inf_s isu_io_inf_def = '{
  ifu     : ifu2isu_def,
  dpu     : dpu2isu_def,
  lsu     : lsu2isu_def,
  exu     : exu2isu_def,
  default : '0
};

typedef struct{
  isu_rf_adr_s wrf[NUM_FU];
  ltid_t ltid[NUM_FU];
  lid_t lid[NUM_FU];
} isu_pip_inf_s;
  
parameter isu_pip_inf_s isu_pip_inf_def = '{
  wrf       : '{default : isu_rf_adr_def},
  ltid      : '{default : '0},
  lid       : '{default : '0},
  default   : '0
};

typedef struct{
  logic en;
  isu_rf_adr_s wrf;
  ltid_t ltid;
  lid_t lid;
  opcode_t opcode;
  imm_t imm;
} isu_spip_inf_s;
  
parameter isu_spip_inf_s isu_spip_inf_def = '{
  wrf       : isu_rf_adr_def,
  opcode    : op_nop,
  default   : '0
};

function automatic void isuPreDecode(
  input ilo_inst_s inst,
  inout isu_thrd_inf_s d
);
  isu_rf_adr_s rrf[3];
  isu_rf_adr_s wrf;

  rrf = '{default : isu_rf_adr_def};
  wrf = isu_rf_adr_def;
  
  d.vec = inst.g.rd[5];
  d.it = it_int;
  d.asyn = '0;
  
  rrf[0].adr = inst.g.rs0;
  rrf[1].adr = inst.g.rs1;
  rrf[2].adr = inst.g.rs2;
  rrf[0].vec = inst.g.rs0[5];
  rrf[1].vec = inst.g.rd[5];
  rrf[2].vec = inst.g.rs2[5];
  rrf[0].ops = opsr;
  rrf[1].ops = opsr;
  rrf[2].ops = opsz;
  
  wrf.adr = inst.g.rd;
  wrf.vec = inst.g.rd[5];
  wrf.wr = '1;
  
  unique casez(inst.g.op)
    default     :  begin end
    iop_lu,
    iop_li      :
    begin
      rrf[1].ops = opsi;
      d.imm = {`TBE(inst.r1w1.rs0), inst.r1w1.rs0, inst.r1w1.imm};
      d.opcode = inst.g.op == iop_lu ? op_lu : op_bp0;
    end
    iop_r1w1si  :
    begin
      rrf[1].ops = opsi;
      d.imm = {`TBE(inst.r1w1.imm), inst.r1w1.imm};
      casez(inst.r1w1.fun)
        2'b00:  d.opcode = iop21_uadd;
        2'b01:  d.opcode = iop21_and;
        2'b10:  d.opcode = iop21_or;
        2'b11:  d.opcode = iop21_xor;
      endcase
    end
    iop_r3w1    :
    begin
      rrf[2].ops = opsr;
      casez(inst.r3w1.fun)
        5'h0:    begin d.opcode = op_fmad; d.it = it_flt; end
        5'h1:    begin d.opcode = op_fmsu; d.it = it_flt; end
        5'h2:    d.opcode = op_mad;
        5'h3:    d.opcode = op_umad;
        5'h4:    d.opcode = op_msu;
        5'h5:    d.opcode = op_umsu;
        5'h6:    d.opcode = op_add3;
      endcase        
    end
    iop_r2w1ti  :
    begin
      d.opcode = opcode_t'(inst.r2w1.fun);
      d.imm = {inst.r2w1.imm, inst.r2w1.rs1};
      if(inst.r2w1.fun[8:4] == 5'b00101)
        rrf[1].ops = opsi;
      if(inst.r2w1.fun[8:6] == 3'b100) begin
        d.it = it_ext;
        d.asyn = d.opcode[5];
        d.opcode[5] = '0;
      end
      if(inst.r2w1.fun[8:4] == 5'b00100)
        d.it = it_flt;
      if(inst.r2w1.fun == iop21_mv2s) begin
        wrf.adr = 'b01;
        wrf.vec = '0;
      end
    end
    iop_memld    :
    begin
      d.imm = {`TBE(inst.ld.os), inst.ld.os};
      d.it = it_lsu;
      d.opcode = opcode_t'({1'b1, inst.ld.ch, inst.ld.lg, inst.ld.fun});
      d.asyn = inst.ld.a;
      rrf[0].vec = inst.g.rd[5];
      rrf[1].ops = opsz;
    end
    iop_memst    :
    begin
      d.imm = {`TBE(inst.ld.os), inst.ld.os};
      d.it = it_lsu;
      d.opcode = opcode_t'({1'b0, inst.ld.ch, inst.ld.lg, inst.ld.fun});
      d.asyn = inst.st.a;
      rrf[0].vec = inst.g.rd[5];
      rrf[1].vec = inst.g.rd[5];
      rrf[1].adr = inst.g.rd;
      wrf.wr = '0;
    end
    iop_cmp2r    :
    begin
      d.vec = inst.g.rs0[5];
      wrf.adr = 'b01;
      wrf.vec = '0;
      rrf[1].vec = inst.g.rd[5];
      rrf[1].adr = inst.g.rd;
      d.opcode = opcode_t'(op_cmp | {inst.cmp2r.m, inst.cmp2r.f, inst.cmp2r.ctyp});
    end
    iop_cmp1ri  :
    begin
      d.vec = inst.g.rs0[5];
      wrf.adr = 'b01;
      wrf.vec = '0;
      d.imm = {`TBE(inst.cmp1ri.imm1), inst.cmp1ri.imm1, inst.cmp1ri.imm0};
      rrf[1].ops = opsi;
      d.opcode = opcode_t'(op_cmp | {inst.cmp1ri.m, inst.cmp1ri.f, inst.cmp1ri.ctyp});
    end
    iop_branch  :
    begin
      d.imm = {`TBE(inst.b.imm1), inst.b.imm1, inst.b.imm0};
      d.opcode = opcode_t'(op_br | {inst.b.c, inst.b.l, inst.b.r});
      wrf.vec = '0;
      d.vec = '0;
      rrf[1].ops = opsz;
      if(!inst.b.r)
        rrf[0].ops = opsc;
      if(!inst.b.l)
        wrf.wr = '0;
    end
    iop_misc    :
    begin
      if(inst.sr.dummy0 == '0) begin
        d.imm = {inst.sr.fea, inst.sr.sr};
        rrf[1].ops = opsz;
        if(inst.sr.tf) begin
          rrf[0].adr = inst.sr.gr;
          rrf[0].vec = inst.sr.gr[5];
          wrf.wr = '0;
          d.opcode = op_mtsr;
        end else begin
          d.opcode = op_mfsr;
        end
      end else if(inst.cop.dummy0 == 2'b10) begin
        d.opcode = opcode_t'(op_cop | inst.cop.fun[4:0]);
        d.imm = {inst.cop.rd, inst.cop.rs, inst.cop.code};
        rrf[1].ops = opsi;
        if(!inst.cop.fun[4])
          rrf[0].ops = opsz;
          wrf.wr = '0;
      end
    end
  endcase
  
  for(int j = 0; j < 3; j++)
    if(!rrf[j].vec) begin
      if(rrf[j].adr == 'h0)
        rrf[j].ops = opsm;
      if(rrf[j].adr == 'h01)
        rrf[j].ops = opsf;
    end
    
  d.rrf = rrf;
  d.wrf = wrf;
  d.vbkCnt = '{default : '0};
  d.sbkCnt = '{default : '0};
  
  for(int i = 0; i < NUM_VRF_BKS; i++)
    for(int j = 0; j < 3; j++)
      if(rrf[j].ops == opsr && rrf[j].vec && rrf[j].adr[WID_VRF_BKS-1:0] == i)
        d.vbkCnt[i]++;
        
  for(int i = 0; i < NUM_SRF_BKS; i++)
    for(int j = 0; j < 3; j++)
      if(rrf[j].ops == opsr && !rrf[j].vec && rrf[j].adr[WID_SRF_BKS-1:0] == i)
        d.sbkCnt[i]++;
endfunction
